if (typeof jQuery === 'undefined') {
    throw new Error('Ace\'s JavaScript requires jQuery')
}

//some basic variables
(function (undefined) {
    if (!('ace' in window)) window['ace'] = {};
    if (!('helper' in window['ace'])) window['ace'].helper = {};
    if (!('vars' in window['ace'])) window['ace'].vars = {};
    window['ace'].vars['icon'] = ' ace-icon ';
    window['ace'].vars['.icon'] = '.ace-icon';
    ace.vars['touch'] = ('ontouchstart' in window);//(('ontouchstart' in document.documentElement) || (window.DocumentTouch && document instanceof DocumentTouch));
})();

//some ace helper functions
(function ($$, undefined) {//$$ is ace.helper
    $$.unCamelCase = function (str) {
        return str.replace(/([a-z])([A-Z])/g, function (match, c1, c2) {
            return c1 + '-' + c2.toLowerCase()
        })
    };
    $$.strToVal = function (str) {
        let res = str.match(/^(?:(true)|(false)|(null)|(\-?[\d]+(?:\.[\d]+)?)|(\[.*\]|\{.*\}))$/i);
        let val = str;
        if (res) {
            if (res[1]) val = true;
            else if (res[2]) val = false;
            else if (res[3]) val = null;
            else if (res[4]) val = parseFloat(str);
            else if (res[5]) {
                try {
                    val = JSON.parse(str)
                } catch (err) {
                }
            }
        }
        return val;
    };
    $$.getAttrSettings = function (elem, attr_list, prefix) {
        if (!elem) return;
        let list_type = attr_list instanceof Array ? 1 : 2;
        //attr_list can be Array or Object(key/value)
        var prefix = prefix ? prefix.replace(/([^\-])$/, '$1-') : '';
        prefix = 'data-' + prefix;

        let settings = {}
        for (let li in attr_list) if (attr_list.hasOwnProperty(li)) {
            let name = list_type === 1 ? attr_list[li] : li;
            let attr_val, attr_name = $$.unCamelCase(name.replace(/[^A-Za-z0-9]{1,}/g, '-')).toLowerCase();

            if (!((attr_val = elem.getAttribute(prefix + attr_name)))) continue;
            settings[name] = $$.strToVal(attr_val);
        }

        return settings;
    }
})(ace.helper);

(function ($, undefined) {
    //sometimes we try to use 'tap' event instead of 'click' if jquery mobile plugin is available
    ace['click_event'] = ace.vars['touch'] && $.fn.tap ? 'tap' : 'click';
})(jQuery);

jQuery(function ($) {
    enableDemoAjax();

    //Load content via ajax
    function enableDemoAjax() {
        if (!$.fn.ace_ajax) return;

        if (window.Pace) {
            window.paceOptions = {
                ajax: true,
                document: true,
                eventLag: false // disabled
                //elements: {selectors: ['.content-wrapper']}
            }
        }

        let demo_ajax_options = {
            'close_active': true,
            'default_url': window.localStorage.getItem("href"),//default hash
            'content_url': function (hash) {
                //***NOTE***
                //this is for Ace demo only, you should change it to return a valid URL
                //please refer to documentation for more info

                if (!hash.match(/^page\//)) return false;
                let path = document.location.pathname;

                let param = '';
                if (hash.indexOf('?') !== -1) {
                    let arr = hash.split('?');
                    hash = arr[0];
                    param = "?" + arr[1];
                }

                if (path.match(/(index\!index\.pjax)?/)) {
                    let temp = path.replace(/(index\!index\.pjax)?/, '');
                    if (!!temp && temp !== '/') {
                        return temp + '/' + hash.replace(/^page\//, '') + param;
                    } else {
                        return temp + hash.replace(/^page\//, '') + param;
                    }
                }
                //for example in Ace PHP demo version we convert "ajax.php#page/dashboard" to "ajax.php?page=dashboard" and load it
                return path + "?" + hash.replace(/\//, "=");
            }
        };

        //for IE9 and below we exclude PACE loader (using conditional IE comments)
        //for other browsers we use the following extra ajax loader options
        if (window.Pace) {
            demo_ajax_options['loading_overlay'] = 'body';//the opaque overlay is applied to 'body'
        }

        //initiate ajax loading on this element( which is .content-wrapper[data-ajax-content=true] in Ace's demo)
        $('[data-ajax-content=true]').ace_ajax(demo_ajax_options);

        //if general error happens and ajax is working, let's stop loading icon & PACE
        $(window).on('error.ace_ajax', function () {
            $('[data-ajax-content=true]').each(function () {
                let $this = $(this);
                if ($this.ace_ajax('working')) {
                    if (window.Pace && Pace.running) Pace.stop();
                    $this.ace_ajax('stopLoading', true);
                }
            })
        })
    }
});
/**
 <b>Load content via Ajax </b>. For more information please refer to documentation #basics/ajax
 */
(function ($, undefined) {
    let ajax_loaded_scripts = {};

    function AceAjax(contentArea, settings) {
        let $contentArea = $(contentArea);
        let self = this;
        $contentArea.attr('data-ajax-content', 'true');

        //get a list of 'data-*' attributes that override 'defaults' and 'settings'
        let attrib_values = ace.helper.getAttrSettings(contentArea, $.fn.ace_ajax.defaults);
        this.settings = $.extend({}, $.fn.ace_ajax.defaults, settings, attrib_values);

        let working = false;
        let $overlay = $();//empty set

        this.force_reload = false;//set jQuery ajax's cache option to 'false' to reload content
        this.loadUrl = function (hash, cache, manual_trigger) {
            let url = false;
            hash = hash.replace(/^(\#\!)?\#/, '');

            this.force_reload = (cache === false)

            if (typeof this.settings.content_url === 'function') url = this.settings.content_url(hash);
            if (typeof url === 'string') this.getUrl(url, hash, manual_trigger);
        };

        this.loadAddr = function (url, hash, cache) {
            this.force_reload = (cache === false);
            this.getUrl(url, hash, false);
        };


        this.reload = function () {
            let hash = $.trim(window.location.hash);
            if (!hash && this.settings.default_url) hash = this.settings.default_url;

            this.loadUrl(hash, false);
        };
        this.post = function (url, data, updateView, extraParams) {
            var url = url || $.trim(location.href.replace(location.hash, ''));
            if (!url) return;
            var data = data || {}
            var updateView = updateView || false;
            this.getUrl(url, null, false, 'POST', data, updateView, extraParams);
        }


        this.getUrl = function (url, hash, manual_trigger, method, data, updateView, extraParams) {
            if (working) {
                return;
            }

            var method = method || 'GET';
            var updateView = (method === 'GET') || (method === 'POST' && !!updateView);
            var data = data || null;

            let event;
            $contentArea.trigger(event = $.Event('ajaxloadstart'), {url: url, hash: hash, method: method, data: data})
            if (event.isDefaultPrevented()) return;

            self.startLoading();

            let ajax_params = method === 'GET' ? {
                'url': url,
                'cache': !this.force_reload
            } : {
                'url': url,
                'method': 'POST',
                'data': data
            };
            if (method === 'POST' && typeof extraParams == 'object') ajax_params = $.extend({}, ajax_params, extraParams);
            $.extend(ajax_params, {
                complete: function (e) {
                    if (e.status === 200) {
                        let result = e.responseText;
                        $contentArea.trigger('ajaxloaddone', {url: url, hash: hash, method: method, data: data});
                        if (method === 'POST') {
                            let event;
                            $contentArea.trigger(event = $.Event('ajaxpostdone', {
                                url: url,
                                data: data,
                                result: result
                            }));
                            if (event.isDefaultPrevented()) updateView = false;
                        }
                        if (updateView) {
                            result = String(result)
                                .replace(/<(title|link)([\s\>])/gi, '<div class="hidden ajax-append-$1"$2')
                                .replace(/<\/(title|link)\>/gi, '</div>')
                            $contentArea.empty().html(result);
                        }
                        if (!manual_trigger && updateView) {
                            $('html,body').animate({scrollTop: 0}, 250);
                        }
                        $contentArea.trigger('ajaxloadcomplete', {url: url, hash: hash, method: method, data: data});
                        let re = /\.(?:\s*)ace(?:_a|A)jax(?:\s*)\((?:\s*)(?:\'|\")loadScripts(?:\'|\")/;
                        if (result.match(re)) self.stopLoading();
                        else self.stopLoading(true);
                        $('div.daterangepicker, div.swal-overlay').remove();
                        $.fn.aceAjax.refreshTreeStatus($('ul.sidebar-menu'));
                    } else if (e.status === 302) {
                        window.location.href = "/login"
                    } else {
                        if(e.responseJSON.message === "NO-PERMISSION"){
                            window.location.href = "#page/unauthorized"
                        }
                        $contentArea.trigger('ajaxloaderror', {url: url, hash: hash, method: method, data: data});
                        self.stopLoading(true);
                    }
                }
            })
            $.ajax(ajax_params);
        };

        let fixPos = false;
        let loadTimer = null;
        this.startLoading = function () {
            if (working) return;
            working = true;

            if (!this.settings.loading_overlay && $contentArea.css('position') === 'static') {
                $contentArea.css('position', 'relative');//for correct icon positioning
                fixPos = true;
            }

            $overlay.remove();
            $overlay = $('<div class="ajax-loading-overlay"><i class="ajax-loading-icon ' + (this.settings.loading_icon || '') + '"></i> ' + this.settings.loading_text + '</div>')

            if (this.settings.loading_overlay === 'body') $('body').append($overlay.addClass('ajax-overlay-body'));
            else if (this.settings.loading_overlay) $(this.settings.loading_overlay).append($overlay);
            else $contentArea.append($overlay);

            if (this.settings.max_load_wait !== false)
                loadTimer = setTimeout(function () {
                    loadTimer = null;
                    if (!working) return;

                    let event;
                    $contentArea.trigger(event = $.Event('ajaxloadlong'));
                    if (event.isDefaultPrevented()) return;

                    self.stopLoading(true);
                }, this.settings.max_load_wait * 1000);
        };

        this.stopLoading = function (stopNow) {
            if (stopNow === true) {
                working = false;

                $overlay.remove();
                if (fixPos) {
                    $contentArea.css('position', '');//restore previous 'position' value
                    fixPos = false;
                }

                if (loadTimer != null) {
                    clearTimeout(loadTimer);
                    loadTimer = null;
                }
            } else {
                $overlay.addClass('almost-loaded');

                $contentArea.one('ajaxscriptsloaded.inner_call', function () {
                    self.stopLoading(true);
                })
            }
        };

        this.working = function () {
            return working;
        };
        ///////////////////////
        this.loadScripts = function (scripts, callback) {
            var scripts = scripts || [];
            $.ajaxPrefilter('script', function (opts) {
                opts.cache = true
            });
            setTimeout(function () {
                //let's keep a list of loaded scripts so that we don't load them more than once!
                function finishLoading() {
                    if (typeof callback === 'function') callback();
                    $('.btn-group[data-toggle="buttons"] > .btn').button();

                    $contentArea.trigger('ajaxscriptsloaded');
                }

                //let deferreds = [];
                let deferred_count = 0;//deferreds count
                let resolved = 0;
                for (let i = 0; i < scripts.length; i++) if (scripts[i]) {
                    (function () {
                        let script_name = "js-" + scripts[i].replace(/[^\w\d\-]/g, '-').replace(/\-\-/g, '-');
                        if (ajax_loaded_scripts[script_name] !== true) deferred_count++;
                    })()
                }

                function nextScript(index) {
                    index += 1;
                    if (index < scripts.length) loadScript(index);
                    else {
                        finishLoading();
                    }
                }

                function loadScript(index) {
                    index = index || 0;
                    if (!scripts[index]) {//could be null sometimes
                        return nextScript(index);
                    }

                    let script_name = "js-" + scripts[index].replace(/[^\w\d\-]/g, '-').replace(/\-\-/g, '-');
                    //only load scripts that are not loaded yet!
                    if (ajax_loaded_scripts[script_name] !== true) {
                        $.getScript(scripts[index])
                            .done(function () {
                                ajax_loaded_scripts[script_name] = true;
                            })
                            //.fail(function() {
                            //})
                            .complete(function () {
                                resolved++;
                                if (resolved >= deferred_count && working) {
                                    finishLoading();
                                } else {
                                    nextScript(index);
                                }
                            })
                    } else {//script previoisly loaded
                        nextScript(index);
                    }
                }

                if (deferred_count > 0) {
                    loadScript();
                } else {
                    finishLoading();
                }
            }, 10)
        }

        /////////////////
        $(window)
            .unbind('hashchange.ace_ajax')
            .on('hashchange.ace_ajax', function (e, manual_trigger) {
                let hash = $.trim(window.location.hash);
                if (!hash || hash.length === 0) return;

                self.loadUrl(hash, null, manual_trigger);
            }).trigger('hashchange.ace_ajax', [true]);

        let hash = $.trim(window.location.hash);
        if (!hash && this.settings.default_url) window.location.hash = this.settings.default_url;

    }//AceAjax

    $.fn.aceAjax = $.fn.ace_ajax = function (option, value, value2, value3, value4) {
        let method_call;
        let $set = this.each(function () {
            let $this = $(this);
            let data = $this.data('ace_ajax');
            let options = typeof option === 'object' && option;
            if (!data) $this.data('ace_ajax', (data = new AceAjax(this, options)));
            if (typeof option === 'string' && typeof data[option] === 'function') {
                if (value4 !== undefined) method_call = data[option](value, value2, value3, value4);
                else if (value3 !== undefined) method_call = data[option](value, value2, value3);
                else if (value2 !== undefined) method_call = data[option](value, value2);
                else method_call === data[option](value);
            }
        });
        return (method_call === undefined) ? $set : method_call;
    };

    $.fn.aceAjax.refreshTreeStatus = function (menu) {
        let path = '#' + window.location.href.split('#')[1];
        let _this = menu.find("a[href='" + path + "']").first();
        menu.find('li').removeClass('active');
        _this.addClass('active');
        _this.parent("li").addClass('active');

        let parent_li = _this.parents('ul.treeview-menu');
        $.each(parent_li, function (index, value) {
            $(value).slideDown(0, function () {
                $(value).addClass('menu-open');
                $(value).parent("li").addClass('active');
            });
        });
    };

    $.fn.aceAjax.defaults = $.fn.ace_ajax.defaults = {
        content_url: false,
        default_url: false,
        loading_icon: 'fa fa-spin fa-spinner fa-2x orange',
        loading_text: '',
        loading_overlay: null,
        update_breadcrumbs: true,
        update_title: true,
        update_active: true,
        close_active: false,
        max_load_wait: false
    }
})(window.jQuery);
